package com.awen.htmlparser.parser;

import com.awen.htmlparser.Exception.ParseException;
import com.awen.htmlparser.rule.CyouHtmlParseRule;
import com.awen.htmlparser.rule.CyouHtmlParseRuleItem;
import com.awen.htmlparser.rule.RuleConfig;
import com.awen.htmlparser.util.PlainTextProcessUtil;
import com.awen.htmlparser.util.Result;
import org.htmlparser.Parser;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import java.util.HashMap;
import java.util.List;

/**
 * CyouHtml解析器
 * User: awen
 * Date: 13-4-8
 * Time: 上午9:55
 * To change this template use File | Settings | File Templates.
 */
public class CopyCyouHtmlUrlParser/* extends AbstractCyouParser */{


    /**
     * 根据解析规则解析指定url
     *
     * @param url
     * @param htmlParseRule
     * @return 返回解析结果 json 格式
     *         {success:true|false,
     *         ['errorCode':'',]
     *         ['msg' : '',]
     *         'data' : {
     *         key : value
     *         }
     *         }
     */
    public static Result parseHtml(String url, CyouHtmlParseRule htmlParseRule) {
        Result result = new Result();
        if (htmlParseRule.isNeedLocateHtml()) {//获取定位的htmlText
            Parser parser = new Parser();
            NodeList nodeList = null;
            try {
                parser.setEncoding(htmlParseRule.getEncoding());
                parser.setURL(url);
            } catch (ParserException e) {
                result.setSuccess(false);
                result.setMsg("解析规则" + htmlParseRule.getName() + "中定位HTMLText时候出错,解析失败.\n失败原因：HTMLParser设置编码异常");
                return result;
            }
            try {
                nodeList = parser.parse(htmlParseRule.getLocateRuleConfig().getNodeFilter());
            } catch (ParserException e) {
                result.setSuccess(false);
                result.setMsg("解析规则" + htmlParseRule.getName() + "中定位HTMLText时候出错,解析失败.\n失败原因：HTMLParser解析异常");
                return result;
            }
            if (htmlParseRule.getLocateRuleConfig().getChild() != null) {
                String htmlText = null;
                try {
                    htmlText = parseItemHtml(htmlParseRule,
                            htmlParseRule.getLocateRuleConfig().getChild(),
                            nodeList.elementAt(htmlParseRule.getLocateRuleConfig().getIndex()).toHtml()
                    );
                } catch (ParserException e) {
                    result.setSuccess(false);
                    result.setMsg("解析规则" + htmlParseRule.getName() + "时候出错,解析失败\n失败原因：HTMLParser解析异常");
                    return result;
                } catch (ParseException e) {
                    result.setSuccess(false);
                    result.setMsg("解析规则" + htmlParseRule.getName() + "中定位HTMLText时候出错,解析失败.\n失败原因：" + e.getMessage());
                    return result;
                }
                return parseHtmlText(htmlText, htmlParseRule);
            } else {
                return parseHtmlText(nodeList.elementAt(htmlParseRule.getLocateRuleConfig().getIndex()).toHtml(), htmlParseRule);
            }
        } else {
            result.setData(new HashMap<String, String>());
            List<CyouHtmlParseRuleItem> ruleItems = htmlParseRule.getRuleItems();
            for (CyouHtmlParseRuleItem cyouHtmlParseRuleItem : ruleItems) {
                Parser parser = new Parser();
                try {
                    parser.setURL(url);
                    parser.setEncoding(cyouHtmlParseRuleItem.getEncoding());

                } catch (ParserException e) {
                    result.setSuccess(false);
                    result.setMsg("解析规则" + htmlParseRule.getName() + "中字段" + cyouHtmlParseRuleItem.getItemName() + "时候出错,解析失败.\n失败原因：HTMLParser设置编码异常");
                    return result;
                }
                NodeList nodeList = null;
                try {
                    nodeList = parser.parse(cyouHtmlParseRuleItem.getRuleConfig().getNodeFilter());
                } catch (ParserException e) {
                    result.setSuccess(false);
                    result.setMsg("解析规则" + htmlParseRule.getName() + "中定位HTMLText时候出错,解析失败.\n失败原因：HTMLParser解析异常");
                    return result;
                }
                if (cyouHtmlParseRuleItem.getRuleConfig().getChild() != null) {
                    try {
                        result.getData().put(
                                cyouHtmlParseRuleItem.getKey(),
                                parseItemHtml(
                                        cyouHtmlParseRuleItem,
                                        cyouHtmlParseRuleItem.getRuleConfig().getChild(),
                                        nodeList.elementAt(cyouHtmlParseRuleItem.getRuleConfig().getIndex()).toHtml().trim()
                                )
                        );
                    } catch (ParserException e) {
                        result.setSuccess(false);
                        result.setMsg("\"解析规则\" + htmlParseRule.getName() + \"中字段\" + cyouHtmlParseRuleItem.getItemName() + \"时候出错,解析失败.\n失败原因：HTMLParser解析异常");
                        return result;
                    } catch (ParseException e) {
                        result.setSuccess(false);
                        result.setMsg("解析规则" + htmlParseRule.getName() + "中字段" + cyouHtmlParseRuleItem.getItemName() + "时候出错,解析失败.\n失败原因：" + e.getMessage());
                        return result;
                    }
                } else {
                    result.getData().put(
                            cyouHtmlParseRuleItem.getKey(),
                            parsePlainText(
                                    cyouHtmlParseRuleItem.getPlainTextFormat(),
                                    nodeList.elementAt(cyouHtmlParseRuleItem.getRuleConfig().getIndex()).toHtml().trim())
                    );
                }
            }
            //打印日志
            result.setMsg("解析成功");
            return result;
        }
    }

    /**
     * 根据解析规则解析指定url
     *
     * @param htmlText
     * @param htmlParseRule
     * @return 返回解析结果 json 格式
     *         {success:true|false,
     *         ['errorCode':'',]
     *         ['msg' : '',]
     *         'data' : {
     *         key : value
     *         }
     *         }
     */
    public static Result parseHtmlText(String htmlText, CyouHtmlParseRule htmlParseRule) {
        Result result = new Result();
        result.setData(new HashMap<String, String>());
        List<CyouHtmlParseRuleItem> ruleItems = htmlParseRule.getRuleItems();
        for (CyouHtmlParseRuleItem cyouHtmlParseRuleItem : ruleItems) {
            Parser parser = new Parser();
            try {
                parser.setInputHTML(htmlText);
                parser.setEncoding((cyouHtmlParseRuleItem.getEncoding()));
            } catch (ParserException e) {
                result.setSuccess(false);
                result.setMsg("解析规则" + htmlParseRule.getName() + "中字段" + cyouHtmlParseRuleItem.getItemName() + "时候出错,解析失败.\n失败原因：HTMLParser设置编码异常");
                return result;
            }
            NodeList nodeList = null;
            try {
                nodeList = parser.parse(cyouHtmlParseRuleItem.getRuleConfig().getNodeFilter());
            } catch (ParserException e) {
                result.setSuccess(false);
                result.setMsg("解析规则" + htmlParseRule.getName() + "中字段" + cyouHtmlParseRuleItem.getItemName() + "时候出错,解析失败.\n失败原因：HTMLParser解析异常");
                return result;
            }
            if (cyouHtmlParseRuleItem.getRuleConfig().getChild() != null) {
                try {
                    result.getData().put(
                            cyouHtmlParseRuleItem.getKey(),
                            parseItemHtml(cyouHtmlParseRuleItem,
                                    cyouHtmlParseRuleItem.getRuleConfig().getChild(),
                                    nodeList.elementAt(cyouHtmlParseRuleItem.getRuleConfig().getIndex()).toHtml())
                    );
                } catch (ParserException e) {
                    result.setSuccess(false);
                    result.setMsg("解析规则" + htmlParseRule.getName() + "中字段" + cyouHtmlParseRuleItem.getItemName() + "时候出错,解析失败.\n失败原因：HTMLParser解析异常");
                    return result;
                } catch (ParseException e) {
                    result.setSuccess(false);
                    result.setMsg("解析规则" + htmlParseRule.getName() + "中字段" + cyouHtmlParseRuleItem.getItemName() + "时候出错,解析失败.\n失败原因：" + e.getMessage());
                    return result;
                }
            } else {
                result.getData().put(
                        cyouHtmlParseRuleItem.getKey(),
                        nodeList.elementAt(cyouHtmlParseRuleItem.getRuleConfig().getIndex()).toPlainTextString()
                );
            }
        }
        //打印日志
        result.setMsg("解析成功");
        return result;
    }

    /**
     * 根据配置的format格式解析element值value
     *
     * @param plainTextFormat
     * @param value
     * @return
     */
    protected static String parsePlainText(String plainTextFormat, String value) {
        String plainTextType = plainTextFormat.split("[:]")[0];
        String[] args = (plainTextFormat.contains(":") && !plainTextFormat.endsWith(":")) ?
                plainTextFormat.split("[:]")[1].split(",") : new String[0];
        return PlainTextProcessUtil.process(plainTextType, value, args);
    }

    /**
     * 对cyouHtmlParseRuleItem通过读取ruleConfig配置（nodeFilter，index等）对当前htmlText进行解析
     *
     * @param ruleConfig
     * @param htmlText
     * @param encoding
     * @param plainTextFormat
     * @return
     * @throws org.htmlparser.util.ParserException
     */
    protected static String parseItemHtml(RuleConfig ruleConfig, String htmlText, String encoding, String plainTextFormat) throws ParserException, ParseException {

        Parser parser = new Parser();
        parser.setInputHTML(htmlText);
        parser.setEncoding(encoding);

        NodeList nodeList = parser.parse(ruleConfig.getNodeFilter());
        if (nodeList == null || nodeList.size() == 0) {
            //throw new ParseException("htmlText不能匹配" + ruleConfig.getPathPattern() + "Pattern");
            return "";
        }
        if (ruleConfig.getChild() != null) {
            return parseItemHtml(ruleConfig.getChild(), nodeList.elementAt(ruleConfig.getIndex()).toHtml().trim(), encoding, plainTextFormat);
        } else {
            return parsePlainText(plainTextFormat, nodeList.elementAt(ruleConfig.getIndex()).toPlainTextString().trim());
        }


    }

    /**
     * 对cyouHtmlParseRuleItem通过读取ruleConfig配置（nodeFilter，index等）对当前htmlText进行解析
     *
     * @param cyouHtmlParseRuleItem
     * @param ruleConfig
     * @param htmlText
     * @return
     * @throws org.htmlparser.util.ParserException
     */
    protected static String parseItemHtml(CyouHtmlParseRuleItem cyouHtmlParseRuleItem, RuleConfig ruleConfig, String htmlText) throws ParserException, ParseException {
        Parser parser = new Parser();
        parser.setInputHTML(htmlText);
        parser.setEncoding(cyouHtmlParseRuleItem.getEncoding());
        NodeList nodeList = parser.parse(ruleConfig.getNodeFilter());
        if (nodeList == null || nodeList.size() == 0) {
            //throw new ParseException("htmlText不能匹配" + ruleConfig.getPathPattern() + "Pattern");
            return "";
        }
        if (ruleConfig.getChild() != null) {
            return parseItemHtml(cyouHtmlParseRuleItem, ruleConfig.getChild(), nodeList.elementAt(ruleConfig.getIndex()).toHtml().trim());
        } else {
            return parsePlainText(cyouHtmlParseRuleItem.getPlainTextFormat(), nodeList.elementAt(ruleConfig.getIndex()).toPlainTextString().trim());
        }
    }

    /**
     * 对cyouHtmlParseRule通过读取ruleConfig配置（nodeFilter，index等）对当前htmlText进行解析
     *
     * @param cyouHtmlParseRule
     * @param ruleConfig
     * @param htmlText
     * @return
     * @throws org.htmlparser.util.ParserException
     */
    protected static String parseItemHtml(CyouHtmlParseRule cyouHtmlParseRule, RuleConfig ruleConfig, String htmlText) throws ParserException, ParseException {
        Parser parser = new Parser();
        parser.setInputHTML(htmlText);
        parser.setEncoding(cyouHtmlParseRule.getEncoding());
        NodeList nodeList = parser.parse(ruleConfig.getNodeFilter());
        if (nodeList == null || nodeList.size() == 0) {
            //throw new ParseException("htmlText不能匹配" + ruleConfig.getPathPattern() + "Pattern");
            return "";
        }
        if (ruleConfig.getChild() != null) {
            return parseItemHtml(cyouHtmlParseRule, ruleConfig.getChild(), nodeList.elementAt(ruleConfig.getIndex()).toHtml().trim());
        } else {
            return parsePlainText(cyouHtmlParseRule.getPlainTextFormat(), nodeList.elementAt(ruleConfig.getIndex()).toPlainTextString().trim());
        }
    }

}
